package co.yixiang.controller.buyer.monitoring;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import co.yixiang.common.properties.ApiProperties;
import co.yixiang.common.utils.ResultUtil;
import co.yixiang.common.vo.ResultMessage;
import co.yixiang.modules.monitoring.entity.domain.Config;
import co.yixiang.modules.monitoring.entity.domain.YxMonitoring;
import co.yixiang.modules.monitoring.entity.vo.YxMonitoringCameraSmallVo;
import co.yixiang.modules.monitoring.entity.vo.YxMonitoringCameraVo;
import co.yixiang.modules.monitoring.service.YxMonitoringService;
import co.yixiang.modules.monitoring.thread.CameraTask;
import co.yixiang.modules.monitoring.thread.CameraThread;
import co.yixiang.modules.monitoring.util.CacheUtil;
import co.yixiang.modules.monitoring.util.Utils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Title CameraController.java
 * @description controller
 * @time 2019年12月16日 上午9:00:27
 * @author wuguodong
 **/

@RestController
@Api(tags = "监控,预览接口")
@RequestMapping("/camera")
public class CameraBuyerController {

	private final static Logger logger = LoggerFactory.getLogger(CameraBuyerController.class);

	@Autowired
	public Config config;// 配置文件bean
	@Autowired
	public YxMonitoringService monitoringService;
	/**
	 * API域名
	 */
	@Autowired
	private ApiProperties apiProperties;

	@ApiOperation(value = "开启视频流")
	@RequestMapping(value = "/cameras/{monitId}/{format}", method = RequestMethod.POST)
	public ResultMessage<YxMonitoringCameraSmallVo> openCamera(@PathVariable Integer monitId,@PathVariable String format) {
		final YxMonitoring monitor = monitoringService.getById(monitId);
		if (ObjectUtil.isEmpty(monitor)) {
			return ResultUtil.error(400,"找不到符合的设备!");
		}
		YxMonitoringCameraVo pojo = new YxMonitoringCameraVo();
		BeanUtil.copyProperties(monitor, pojo);
		pojo.setFormat(format);
		// 返回结果
		Map<String, Object> map = new LinkedHashMap<String, Object>();
		// openStream返回结果
		Map<String, Object> openMap = new HashMap<>();
		// ip格式校验
		//if (!Utils.isTrueIp(pojo.getHost())) { return ResultUtil.error(2, "ip格式输入错误"); }
		// 开始时间校验
		if (ObjectUtil.isNotEmpty(pojo.getStarttime()) && ObjectUtil.isNotEmpty(pojo.getEndtime())) {
			// 结束时间要大于开始时间
			if (pojo.getEndtime().getTime() - pojo.getStarttime().getTime() < 0) {
				return ResultUtil.error(5, "endtime需要大于starttime");
			}
		}
		// 获取当前时间
		String opentime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis());
		pojo.setOpentime(opentime);
		Set<String> keys = CacheUtil.STREATMAP.keySet();
		// 缓存是否为空
		if (0 == keys.size()) {
			// 开始推流
			openMap = openStream(pojo);
			if (Integer.parseInt(openMap.get("errorcode").toString()) != 0) {
				return ResultUtil.error(Integer.parseInt(openMap.get("errorcode").toString()), openMap.get("message").toString());
			}
		} else {
			// 是否存在的标志；false：不存在；true：存在
			boolean sign = false;
			if (null == pojo.getStarttime()) {
				// 直播流
				for (String key : keys) {
					if (pojo.getHost().equals(CacheUtil.STREATMAP.get(key).getHost()) && pojo.getChannel().equals(CacheUtil.STREATMAP.get(key).getChannel()) && null == CacheUtil.STREATMAP.get(key).getStarttime()) {// 存在直播流
						pojo = CacheUtil.STREATMAP.get(key);
						sign = true;
						break;
					}
				}
				if (sign) {
					// 存在
					pojo.setCount(pojo.getCount() + 1);
					pojo.setOpentime(opentime);
				} else {
					// 开始推流
					openMap = openStream(pojo);
					if (Integer.parseInt(openMap.get("errorcode").toString()) != 0) {
						return ResultUtil.error(Integer.parseInt(openMap.get("errorcode").toString()), openMap.get("message").toString());
					}
				}
			} else {
				// 历史流
				for (String key : keys) {
					if (pojo.getHost().equals(CacheUtil.STREATMAP.get(key).getHost()) && CacheUtil.STREATMAP.get(key).getStarttime() != null) {// 存在历史流
						sign = true;
						pojo = CacheUtil.STREATMAP.get(key);
						break;
					}
				}
				if (sign && pojo.getCount() == 0) {
					return ResultUtil.error(9, "设备正在结束回放,请稍后再试");
				} else if (sign && pojo.getCount() != 0) {
					return ResultUtil.error(8, "设备正在进行回放,请稍后再试");
				} else {
					// 开始推流
					openMap = openStream(pojo);
					if (Integer.parseInt(openMap.get("errorcode").toString()) != 0) {
						return ResultUtil.error(Integer.parseInt(openMap.get("errorcode").toString()), openMap.get("message").toString());
					}
				}
			}
		}
		YxMonitoringCameraSmallVo result = new YxMonitoringCameraSmallVo();
		BeanUtil.copyProperties(pojo, result);
		if (ObjectUtil.isNotEmpty(result.getRtmp()) && "rtmp".equals(format)) {
			result.setHls("https://zhihui.yvliang.com/hls/"+result.getToken()+"/index.m3u8");
		}
		if (ObjectUtil.isNotEmpty(result.getRtmp()) && "flv".equals(format)) {
			result.setFlv("https://zhihui.yvliang.com/flv?app=liveapp&stream="+result.getToken());
		}
		return ResultUtil.data(result);
	}

	/**
	 *
	 * @param cameraPojo
	 * @return
	 */
	private Map<String, Object> openStream(YxMonitoringCameraVo cameraPojo) {
		Map<String, Object> map = new HashMap<>();
		// 生成token
		String token = UUID.randomUUID().toString();
		cameraPojo.setToken(token);
		cameraPojo.setCount(1);
		//String IP = Utils.IpConvert(cameraPojo.getHost());
		String IP = cameraPojo.getHost();
		boolean sign = false;// 该nvr是否再回放，true：在回放；false： 没在回放
		// 历史流
		if (ObjectUtil.isNotEmpty(cameraPojo.getStarttime())) {
			if (ObjectUtil.isNotEmpty(cameraPojo.getEndtime())) {
				cameraPojo.setRtsp("rtsp://" + cameraPojo.getUsername() + ":" + cameraPojo.getPasswd() + "@" + IP + ":"+ cameraPojo.getPort() +"/Streaming/tracks/" + (Integer.parseInt(cameraPojo.getChannel()) - 32) + "01?starttime=" + cameraPojo.getStarttime().toString().substring(0, 8) + "t" + cameraPojo.getStarttime().toString().substring(8) + "z'&'endtime=" + cameraPojo.getStarttime().toString().substring(0, 8) + "t" + cameraPojo.getStarttime().toString().substring(8) + "z");
			} else {
				String startTime = cameraPojo.getStarttime().toString();
				String endTime = cameraPojo.getEndtime().toString();
				cameraPojo.setRtsp("rtsp://" + cameraPojo.getUsername() + ":" + cameraPojo.getPasswd() + "@" + IP + ":"+cameraPojo.getPort()+"/Streaming/tracks/" + (Integer.parseInt(cameraPojo.getChannel()) - 32) + "01?starttime=" + startTime.substring(0, 8) + "t" + startTime.substring(8) + "z'&'endtime=" + endTime.substring(0, 8) + "t" + endTime.substring(8) + "z");
			}
//			rtmp = "rtmp://" + Utils.IpConvert(config.getPush_host()) + ":" + config.getPush_port() + "/history/" + token;
			//rtmp = "rtmp://" + Utils.IpConvert(config.getPush_host()) + ":" + config.getPush_port() + "/hls/test";
			cameraPojo.setRtmp("rtmp://" + Utils.IpConvert(config.getPush_host()) + ":" + config.getPush_port() + "/hls/test");
			cameraPojo.setUrl(cameraPojo.getRtmp());
			if (!"127.0.0.1".equals(config.getHost_extra())) {
				// url = "rtmp://" + Utils.IpConvert(config.getHost_extra()) + ":" + config.getPush_port() + "/hls/" + token;
				cameraPojo.setUrl("rtmp://" + Utils.IpConvert(config.getHost_extra()) + ":" + config.getPush_port() + "/hls/" + token);
			}
		} else {
			// 直播流
			//rtsp = "rtsp://" + username + ":" + password + "@" + IP + ":554/h264/ch" + channel + "/" + stream + "/av_stream";
			// rtsp = "rtsp://admin:iunion666@118.114.250.242:1554/Streaming/Channels/101?transportmode=multicast";
			//rtmp = "rtmp://" + Utils.IpConvert(config.getPush_host()) + ":" + config.getPush_port() + "/hls/" + token;
			cameraPojo.setRtsp("rtsp://"+cameraPojo.getUsername()+":"+cameraPojo.getPasswd()+"@"+IP+":"+cameraPojo.getPort()+"/Streaming/Channels/"+cameraPojo.getChannel()+"?transportmode=multicast");
			cameraPojo.setRtmp("rtmp://" + Utils.IpConvert(config.getPush_host()) + ":" + config.getPush_port() + "/hls/" + token);
			if("flv".equals(cameraPojo.getFormat())) {
				cameraPojo.setRtmp("rtmp://" + Utils.IpConvert(config.getPush_host()) + ":" + config.getPush_port() + "/liveapp/" + token);
			}
			cameraPojo.setUrl(cameraPojo.getRtmp());
			if (!"127.0.0.1".equals(config.getHost_extra())) {
				// url = "rtmp://" + Utils.IpConvert(config.getHost_extra()) + ":" + config.getPush_port() + "/hls/" + token;
				cameraPojo.setRtsp("rtmp://" + Utils.IpConvert(config.getHost_extra()) + ":" + config.getPush_port() + "/hls/" + token);
				if("flv".equals(cameraPojo.getFormat())) {
					cameraPojo.setRtmp("rtmp://" + Utils.IpConvert(config.getHost_extra()) + ":" + config.getPush_port() + "/liveapp/" + token);
				}
			}
		}
		// 解决ip输入错误时，grabber.start();出现阻塞无法释放grabber而导致后续推流无法进行；
		Socket rtspSocket = new Socket();
		Socket rtmpSocket = new Socket();
		// 建立TCP Scoket连接，超时时间1s，如果成功继续执行，否则return
		try {
			rtspSocket.connect(new InetSocketAddress(cameraPojo.getHost(), cameraPojo.getPort()), 1000);
		} catch (IOException e) {
			logger.error("与拉流IP：   " + cameraPojo.getHost() + "   端口：   "+ cameraPojo.getPort() +"    建立TCP连接失败！");
			map.put("errorcode", 6);
			map.put("message", "与拉流IP：   " + cameraPojo.getHost() + "   端口：   "+ cameraPojo.getPort() +"    建立TCP连接失败！");
			return map;
		}
		try {
			rtmpSocket.connect(new InetSocketAddress(Utils.IpConvert(config.getPush_host()), Integer.parseInt(config.getPush_port())), 1000);
		} catch (IOException e) {
			logger.error("与推流IP：   " + config.getPush_host() + "   端口：   " + config.getPush_port() + " 建立TCP连接失败！");
			map.put("errorcode", 7);
			map.put("message", "与推流IP:" + config.getPush_host() + " 端口: " + config.getPush_port() + " 建立连接失败,请检查nginx服务");
			return map;
		}
		// 执行任务
		CameraThread.MyRunnable job = new CameraThread.MyRunnable(cameraPojo);
		CameraThread.MyRunnable.es.execute(job);
		CameraTask.JOBMAP.put(token, job);
		map.put("errorcode", 0);
		map.put("message", "打开视频流成功");
		return map;
	}

	@ApiOperation(value = "关闭视频流")
	@DeleteMapping(value = "/cameras/{tokens}")
	public ResultMessage<String> closeCamera(@PathVariable("tokens") String tokens) {
		if (ObjectUtil.isNotEmpty(tokens)) {
			String[] tokenArr = tokens.split(",");
			for (String token : tokenArr) {
				if (CameraTask.JOBMAP.containsKey(token) && CacheUtil.STREATMAP.containsKey(token)) {
					// 回放手动关闭
					if (null != CacheUtil.STREATMAP.get(token).getStarttime()) {
						if (0 == CacheUtil.STREATMAP.get(token).getCount() - 1) {
							CacheUtil.PUSHMAP.get(token).setExitcode(1);
							CacheUtil.STREATMAP.get(token).setCount(CacheUtil.STREATMAP.get(token).getCount() - 1);
						} else {
							CacheUtil.STREATMAP.get(token).setCount(CacheUtil.STREATMAP.get(token).getCount() - 1);
							logger.info("当前设备正在进行回放，使用人数为" + CacheUtil.STREATMAP.get(token).getCount() + " 设备信息：[ip："
									+ CacheUtil.STREATMAP.get(token).getHost() + " channel:"
									+ CacheUtil.STREATMAP.get(token).getChannel() + " stream:"
									+ CacheUtil.STREATMAP.get(token).getStarttime() + " statrtime:"
									+ CacheUtil.STREATMAP.get(token).getEndtime() + " endtime:"
									+ CacheUtil.STREATMAP.get(token).getEndtime() + " url:"
									+ CacheUtil.STREATMAP.get(token).getUrl() + "]");
						}
					} else {
						if (0 < CacheUtil.STREATMAP.get(token).getCount()) {
							// 人数-1
							CacheUtil.STREATMAP.get(token).setCount(CacheUtil.STREATMAP.get(token).getCount() - 1);
							logger.info("关闭成功 当前设备使用人数为" + CacheUtil.STREATMAP.get(token).getCount() + " 设备信息：[ip："
									+ CacheUtil.STREATMAP.get(token).getHost() + " channel:"
									+ CacheUtil.STREATMAP.get(token).getChannel() + " stream:"
									+ CacheUtil.STREATMAP.get(token).getStarttime() + " statrtime:"
									+ CacheUtil.STREATMAP.get(token).getEndtime() + " endtime:"
									+ CacheUtil.STREATMAP.get(token).getEndtime() + " url:"
									+ CacheUtil.STREATMAP.get(token).getUrl() + "]");
						}
					}

				}
			}
		}
		return ResultUtil.success();
	}

	@ApiOperation(value = "获取视频流")
	@RequestMapping(value = "/cameras", method = RequestMethod.GET)
	public ResultMessage<Map<String, YxMonitoringCameraSmallVo>> getCameras() {
		logger.info("获取视频流信息：" + CacheUtil.STREATMAP.toString());
		Map<String, YxMonitoringCameraSmallVo> smallVoMap = new HashMap<>();
		for (Map.Entry<String, YxMonitoringCameraVo> entry : CacheUtil.STREATMAP.entrySet()) {
			smallVoMap.put(entry.getKey(), BeanUtil.copyProperties(entry.getValue(),YxMonitoringCameraSmallVo.class));
		}
		return ResultUtil.data(smallVoMap);
	}

	@ApiOperation(value = "视频流保活")
	@RequestMapping(value = "/cameras/{tokens}", method = RequestMethod.PUT)
	public ResultMessage<String> keepAlive(@PathVariable("tokens") String tokens) {
		// 校验参数
		if (ObjectUtil.isNotEmpty(tokens)) {
			String[] tokenArr = tokens.split(",");
			for (String token : tokenArr) {
				YxMonitoringCameraVo cameraPojo = new YxMonitoringCameraVo();
				// 直播流token
				if (null != CacheUtil.STREATMAP.get(token)) {
					cameraPojo = CacheUtil.STREATMAP.get(token);
					// 更新当前系统时间
					cameraPojo.setOpentime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis()));
					logger.info("保活成功 设备信息：[ip：" + cameraPojo.getHost() + " channel:" + cameraPojo.getChannel() + " starttime:" + cameraPojo.getStarttime() + " endtime:" + cameraPojo.getEndtime() + " url:" + cameraPojo.getUrl() + "]");
				}
			}
		}
		return ResultUtil.success();
	}

	@ApiOperation(value = "获取服务信息")
	@RequestMapping(value = "/status", method = RequestMethod.GET)
	public ResultMessage<Map<String, Object>> getConfig() {
		// 获取当前时间
		long nowTime = System.currentTimeMillis();
		String upTime = (nowTime - CacheUtil.STARTTIME) / (1000 * 60 * 60) + "h"
				+ (nowTime - CacheUtil.STARTTIME) % (1000 * 60 * 60) / (1000 * 60) + "m"
				+ (nowTime - CacheUtil.STARTTIME) % (1000 * 60 * 60) / (1000) + "s";
		logger.info("获取服务信息：" + config.toString() + ";服务运行时间：" + upTime);
		Map<String, Object> status = new HashMap<String, Object>();
		status.put("config", config);
		status.put("uptime", upTime);
		return ResultUtil.data(status);
	}

}
